#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 时间     : 2021-08-18 17:39
# 作者     : DL (584054432@qq.com)
# 网址     : https://gitee.com/dingliangPython/
# 软件版本 : Python3.7.3
# 功能     ：


import logging

import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp


class TcpClient(object):
    """docstring for TcpClient"""

    def __init__(self, config):
        super(TcpClient, self).__init__()
        self._id = config.get('id', 1)
        self.host = config.get('host', '127.0.0.1')
        self.port = int(config.get('port', 502))
        self.timeout = float(config.get('timeout', 5))
        self.log = logging.getLogger('main.modbus_tcp')
        self.client = self.connect()

    # 连接
    def connect(self):
        try:
            client = modbus_tcp.TcpMaster(self.host, self.port, self.timeout)
            client.set_timeout(self.timeout)
            result = client.open()
            self.log.info(
                    "初始化连接ModbusTcp主机：{}，端口：{}，站点：{}，连接超时：{}，连接成功。。。".format(self.host, self.port, self._id,
                                                                             self.timeout))
            return client
        except Exception as e:
            self.log.error("初始化连接ModbusTcp主机：{}，端口：{}，站点：{}，连接超时：{}，连接异常：{}。。。".format(self.host, self.port, self._id,
                                                                                       self.timeout, e))

    # 获取功能码
    def get_code(self, address):
        # 线圈状态
        if address in range(0, 9999):
            return cst.READ_COILS
        # 离散输入状态
        if address in range(10001, 19999):
            return cst.READ_DISCRETE_INPUTS
        # 保持寄存器
        if address in range(40001, 49999):
            return cst.READ_HOLDING_REGISTERS
        # 输入寄存器
        if address in range(30001, 39999):
            return cst.READ_INPUT_REGISTERS

    def get_address(self, address, code):
        if code == cst.READ_COILS:
            return address
        if code == cst.READ_DISCRETE_INPUTS:
            return address - 10000
        if code == cst.READ_HOLDING_REGISTERS:
            return address - 40000
        if code == cst.READ_INPUT_REGISTERS:
            return address - 30000

    # 读取数据
    def read(self, address, count = 1, code = None):
        try:
            if not self.client:
                return
            code = code if code != None else self.get_code(address)
            addr = self.get_address(address, code) - 1  # 从0开始
            self.log.debug("ID:{},功能码：{}，地址：{}，数量：{}".format(self._id, code, addr, count))
            data = self.client.execute(self._id, code, addr, count)
            return data
        except Exception as e:
            self.log.warning("地址：{}，读取异常：{}".format(address, e))

    # 写入数据
    def write(self, address, value = 0, code = 6):
        if not self.client:
            return
        try:
            count = len(value) if isinstance(value, list) else 1
            data = self.client.execute(self._id, code, address, count, value)
            return data
        except Exception as e:
            self.log.warning("地址：{}，写入异常：{}".format(address, e))


if __name__ == "__main__":
    import time, time_ext

    config = {'host': '127.0.0.1', 'port': 502, 'id': 1}
    client = TcpClient(config)
    value = 0xFFFF
    while True:
        data = client.read(0)
        print("时间：{}，读取值：{}".format(time_ext.get_str_datetime(), data))
        value -= 1
        result = client.write(0, value)
        print(result)
        time.sleep(3)
# try:
#     # 连接MODBUS TCP从机
#     master = modbus_tcp.TcpMaster(host="127.0.0.1")
#     master.set_timeout(5.0)
#     logger.info("connected")
#     # 读保持寄存器
#     demo1 = master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 9)
#     print(demo1)
#     # 读输入寄存器
#     logger.info(master.execute(3, cst.READ_INPUT_REGISTERS, 0, 9, output_value=1))
#     # 读线圈寄存器
#     logger.info(master.execute(2, cst.READ_COILS, 0, 8))
#     logger.info(master.execute(2, cst.WRITE_SINGLE_COIL, 1, output_value=2))
#     # 读离散输入寄存器
#     logger.info(master.execute(4, cst.READ_DISCRETE_INPUTS, 0, 8))
#     # 单个读写寄存器操作
#     # 写寄存器地址为0的保持寄存器
#     logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, output_value=20))
#     logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 8))
#     # 写寄存器地址为0的线圈寄存器，写入内容为0（位操作）
#     logger.info(master.execute(2, cst.WRITE_SINGLE_COIL, 0, output_value=2))
#     logger.info(master.execute(2, cst.READ_COILS, 0, 1))
#     # # 多个寄存器读写操作
#     # # 写寄存器起始地址为0的保持寄存器，操作寄存器个数为4
#     logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 0, output_value=[20,21,22,23]))
#     logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 4))
#     # # 写寄存器起始地址为0的线圈寄存器
#     logger.info(master.execute(2, cst.WRITE_MULTIPLE_COILS, 0, output_value=[0,0,0,1]))
#     logger.info(master.execute(2, cst.READ_COILS, 0, 4))
# except modbus_tk.modbus.ModbusError as e:
#     logger.error("%s- Code=%d" % (e, e.get_exception_code()))
#